package com.simons.common.utils.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.simons.common.exception.CommonErrorType;
import com.simons.common.exception.CommonException;

import lombok.extern.log4j.Log4j2;

@Log4j2
public class ReflectUtil {

	private ReflectUtil(){
		//私有构造
	}
	
	public static <T> T getInstance(Class<T> clazz) throws CommonException{
		try {
			return clazz.newInstance();
		} catch (InstantiationException e) {
			log.error("对象实例化失败", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_INSTANCE_ERROR);
		} catch (IllegalAccessException e) {
			log.error("对象实例化失败", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_INSTANCE_ERROR);
		}
	}
	
	@SuppressWarnings({ "rawtypes" })
	public static <T> List<Field> getField(T v)  {
		if(v == null){
			return Collections.emptyList();
		}
		List<Field> result = new ArrayList<Field>();
		
		Class clazz = v.getClass();
		Field[] fields = clazz.getDeclaredFields();
		
		List<Field> fieldList = Arrays.asList(fields);
		result.addAll(fieldList);
		Class superClazz = clazz.getSuperclass();
		while (superClazz != null){
			Field[] superClazzFields = superClazz.getDeclaredFields();
			List<Field> superClazzFieldList = Arrays.asList(superClazzFields);
			result.addAll(superClazzFieldList);
			
			superClazz = superClazz.getSuperclass();
		}
		
		return result;
	}
	
	@SuppressWarnings({ "rawtypes" })
	public static <T> T resetValue(T v) throws CommonException {
		if(v == null){
			return null;
		}
		List<Field> fieldList = getField(v);
		
		try{
			for(Field field : fieldList){
				field.setAccessible(true);
				Object value = field.get(v);
				if(value == null){
					Class typeClazz = field.getType();
					field.set(v, typeClazz.newInstance());
				}
			}
		} catch (IllegalArgumentException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (IllegalAccessException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (InstantiationException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		}
			
		return v;
	}
	
	/**
     * 反射调用指定构造方法创建对象
     * 
     * @param clazz
     *            对象类型
     * @param argTypes
     *            参数类型
     * @param args
     *            构造参数
     * @return 返回构造后的对象
	 * @throws CommonException 
     * @throws SecurityException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * 
     */
    public static <T> T invokeConstructor(Class<T> clazz, Class<?>[] argTypes,
            Object[] args) throws CommonException  {
        Constructor<T> constructor;
		try {
			constructor = clazz.getConstructor(argTypes);
		} catch (NoSuchMethodException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (SecurityException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		}
        try {
			return constructor.newInstance(args);
		} catch (InstantiationException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (IllegalAccessException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (IllegalArgumentException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		} catch (InvocationTargetException e) {
			log.error("", e);
			throw new CommonException(CommonErrorType.COMMON_REFLECT_RESET_ERROR);
		}
    }
 
}

